﻿using System.Collections.Generic;
using System.IO;
using System;
using UnityEngine;
using UnityEditor;
using Object = UnityEngine.Object;
public class Packer : EditorWindow
{
    [MenuItem("Tools/Packer")]
    public static void ShowPacker()
    {
        GetWindow<Packer>(false, "Packer", true);
    }

    [MenuItem("Assets/Build", false, 10001)]
    public static void Build()
    {
        setting.Build(Selection.assetGUIDs, encryptLua);
    }

    const string KEY_ENCRYPT_LUA = "PackerSetting.EncryptLua";
    static bool m_EncryptLuaInied = false;
    static bool m_EncryptLua = false;
    static bool encryptLua
    {
        get
        {
            if (!m_EncryptLuaInied)
            {
                m_EncryptLua = PlayerPrefs.GetInt(KEY_ENCRYPT_LUA, 0) == 0 ? false : true;
                m_EncryptLuaInied = true;
            }
            return m_EncryptLua;
        }
        set
        {
            if (m_EncryptLua != value)
            {
                m_EncryptLua = value;
                PlayerPrefs.SetInt(KEY_ENCRYPT_LUA, m_EncryptLua ? 1 : 0);
            }
        }
    }

    public static Packer instance
    { get; private set; }

    public static void Refresh()
    {
        if (instance != null)
            instance.Repaint();
    }

    static PackerSetting m_Setting;
    public static PackerSetting setting
    {
        get
        {
            if (m_Setting != null)
                return m_Setting;

            var guids = AssetDatabase.FindAssets("t:PackerSetting");
            if (guids.Length != 0)
            {
                var path = AssetDatabase.GUIDToAssetPath(guids[0]);
                m_Setting = AssetDatabase.LoadAssetAtPath<PackerSetting>(path);
                return m_Setting;
            }

            Debug.LogError("PackerSetting is null!");
            return m_Setting;
        }
    }

    PackerGUI m_GUI;
    public PackerGUI gui
    {
        get
        {
            if (m_GUI != null)
                return m_GUI;

            var guids = AssetDatabase.FindAssets("t:PackerGUI");
            if (guids.Length != 0)
            {
                var path = AssetDatabase.GUIDToAssetPath(guids[0]);
                m_GUI = AssetDatabase.LoadAssetAtPath<PackerGUI>(path);
                return m_GUI;
            }

            Debug.LogError("PackGUI is null!");
            return m_GUI;
        }
    }

    void OnEnable()
    {
        instance = this;
    }

    void OnDisable()
    {
        instance = null;
    }

    bool HasFocus()
    {
        return focusedWindow == this;
    }

    void ShowInspector(Object obj)
    {
        Selection.activeObject = obj;

        var type = typeof(EditorWindow).Assembly.GetType("UnityEditor.InspectorWindow");
        var window = GetWindow(type);
        window.ShowTab();
    }

    void OnGUI()
    {
        DrawMenu();
        DrawItems();
    }

    void DrawMenu()
    {
        EditorGUILayout.BeginHorizontal(EditorStyles.toolbar, GUILayout.ExpandWidth(true));
        //{
        if (GUILayout.Button(" Build All ", EditorStyles.toolbarButton))
        {
            if (EditorUtility.DisplayDialog("提示", "确定打包所有文件？", "确定", "取消"))
                setting.BuildAll(false, encryptLua);
            GUIUtility.ExitGUI();
        }

        if (GUILayout.Button(" Rebuild All ", EditorStyles.toolbarButton))
        {
            if (EditorUtility.DisplayDialog("提示", "确定重新打包所有文件？", "确定", "取消"))
                    setting.BuildAll(true, encryptLua);
            GUIUtility.ExitGUI();
        }

          //  if (GUILayout.Button(" CopyLua ", EditorStyles.toolbarButton))
          //  {
          //      setting.CopyLua(encryptLua);
          //  }
          //
          //  encryptLua = GUILayout.Toggle(encryptLua, "Encrypt Lua");

            GUILayout.FlexibleSpace();

            if (GUILayout.Button(" Setting ", EditorStyles.toolbarButton))
                ShowInspector(setting);
       // }
        EditorGUILayout.EndHorizontal();

    }

    Vector2 m_ScrollPos = Vector2.zero;
    List<string> m_LastItems = new List<string>();
    List<string> m_NowItems = new List<string>();

    void DrawItems()
    {
        m_ScrollPos = EditorGUILayout.BeginScrollView(m_ScrollPos);
        DrawItems(setting.rootPath, 0);
        EditorGUILayout.EndScrollView();

        var temp = m_LastItems;
        m_LastItems = m_NowItems;
        m_NowItems = temp;
        m_NowItems.Clear();
    }

    void DrawItems(string floder, int deep)
    {
        var dirs = Directory.GetDirectories(floder);
        foreach (var dir in dirs)
        {
            DrawFloader(dir, deep);
        }

        var files = Directory.GetFiles(floder);
        foreach (var file in files)
        {
            if (file.EndsWith(".meta"))
                continue;

            DrawAsset(file, deep);
        }
    }

    void DrawFloader(string path, int deep)
    {
        var guid = AssetDatabase.AssetPathToGUID(path);
        m_NowItems.Add(guid);

        bool expend = IsExpend(path);
        Rect itemRect = EditorGUILayout.BeginHorizontal(GetItemStyle(path));
        {
            GUILayout.Space(22 * deep);
            if (expend != GUILayout.Toggle(expend, "", gui.GetStyle("Expend")))
                SetExpend(path, !expend);

            Texture icon = AssetDatabase.GetCachedIcon(path);
            EditorGUIUtility.SetIconSize(new Vector2(16f, 16f));
            GUILayout.Label(icon, GUILayout.ExpandWidth(false));

            GUI.color = GetFloderColor(guid);
            GUILayout.Label(Path.GetFileName(path), GUILayout.ExpandWidth(false));
            GUI.color = Color.white;
        }
        EditorGUILayout.EndHorizontal();

        ProcessSelect(path, itemRect);
        RightClickMenu(itemRect);

        if (expend)
            DrawItems(path, deep + 1);
    }

    Color GetFloderColor(string guid)
    {
        var pack = setting.GetFloderPackType(guid);
        switch (pack)
        {
            case FloderPackType.Copy:
                return Color.yellow;
            case FloderPackType.BundleTogether:
                return Color.cyan;
            case FloderPackType.BundleEachFile:
                return Color.green;
            default:
                return Color.white;
        }
    }

    void DrawAsset(string path, int deep)
    {
        var guid = AssetDatabase.AssetPathToGUID(path);
        m_NowItems.Add(guid);

        Rect itemRect = EditorGUILayout.BeginHorizontal(GetItemStyle(path));
        {
            GUILayout.Space(22 * deep + 17);

            Texture icon = AssetDatabase.GetCachedIcon(path);
            EditorGUIUtility.SetIconSize(new Vector2(16f, 16f));
            GUILayout.Label(icon, GUILayout.ExpandWidth(false));

            GUI.color = GetFileColor(guid);
            GUILayout.Label(Path.GetFileName(path), GUILayout.ExpandWidth(false));
            GUI.color = Color.white;
        }
        EditorGUILayout.EndHorizontal();

        ProcessSelect(path, itemRect);
        RightClickMenu(itemRect);
    }

    Color GetFileColor(string guid)
    {
        var pack = setting.GetFilePackType(guid);
        switch (pack)
        {
            case FilePackType.None:
                return Color.gray;
            case FilePackType.Copy:
                return Color.yellow;
            case FilePackType.Bundle:
                return Color.green;
            default:
                return Color.white;
        }
    }

    HashSet<string> m_ExpendItems = new HashSet<string>();
    void SetExpend(string path, bool expend)
    {
        var guid = AssetDatabase.AssetPathToGUID(path);
        if (expend)
            m_ExpendItems.Add(guid);
        else
            m_ExpendItems.Remove(guid);
    }

    bool IsExpend(string path)
    {
        return m_ExpendItems.Contains(AssetDatabase.AssetPathToGUID(path));
    }
    
    GUIStyle GetItemStyle(string path)
    {
        string name;
        if (!IsSelected(path))
            name = "TreeItemUnselect";
        else
            name = HasFocus() ? "TreeItemSelectBlue" : "TreeItemSelectGray";
        return gui.GetStyle(name);
    }

    List<string> m_SelectedItems = new List<string>();

    bool IsSelected(string path)
    {
        var guid = AssetDatabase.AssetPathToGUID(path);
        return m_SelectedItems.Contains(guid);
    }

    void ProcessSelect(string path, Rect itemRect)
    {
        if (!IsRectClicked(itemRect))
            return;
        
        var guid = AssetDatabase.AssetPathToGUID(path);
        switch (Event.current.button)
        {
                // 左键
            case 0:
                if (Event.current.control)
                {
                    if (m_SelectedItems.Contains(guid))
                        m_SelectedItems.Remove(guid);
                    else
                        m_SelectedItems.Add(guid);
                }
                else if (Event.current.shift)
                    ShiftSelect(path);
                else
                {
                    m_SelectedItems.Clear();
                    m_SelectedItems.Add(guid);
                }
                break;
                // 右键
            case 1:
                if (!m_SelectedItems.Contains(guid))
                {
                    m_SelectedItems.Clear();
                    m_SelectedItems.Add(guid);
                }
                else
                    return;
                break;
            default:
                return;
        }
        
        Object[] objs = new Object[m_SelectedItems.Count];
        for (int i = 0; i < m_SelectedItems.Count; ++i)
        {
            var guid2 = m_SelectedItems[i];
            var path2 = AssetDatabase.GUIDToAssetPath(guid2);
            if (Directory.Exists(path2))
            {
                var item = CreateInstance<PackerFloderItem>();
                item.guid = guid2;
                objs[i] = item;
            }
            else
            {
                var item = CreateInstance<PackerFileItem>();
                item.guid = guid2;
                objs[i] = item;
            }
        }
        Selection.objects = objs;

        Repaint();
    }

    void ShiftSelect(string path)
    {
        var guid = AssetDatabase.AssetPathToGUID(path);
        if (m_SelectedItems.Count == 0)
        {
            m_SelectedItems.Add(guid);
            return;
        }

        int fromIndex = m_LastItems.IndexOf(m_SelectedItems[0]);
        int toIndex = m_LastItems.IndexOf(guid);

        if (fromIndex == -1 || toIndex == -1 || fromIndex == toIndex)
            return;

        m_SelectedItems.Clear();
        int step = fromIndex < toIndex ? 1 : -1;
        toIndex += step;
        for (int i = fromIndex; i != toIndex; i += step)
        {
            m_SelectedItems.Add(m_LastItems[i]);
        }
    }

    bool IsRectClicked(Rect rect)
    {
        return Event.current.type == EventType.MouseDown && MouseInRect(rect);
    }

    bool MouseInRect(Rect rect)
    {
        return rect.Contains(Event.current.mousePosition);
    }
    
    bool IsControl()
    {
        return (Application.platform == RuntimePlatform.WindowsEditor && Event.current.control) ||
            (Application.platform == RuntimePlatform.OSXEditor && Event.current.command);
    }

    void RightClickMenu(Rect itemRect)
    {
        if (Event.current.type == EventType.MouseUp && Event.current.button == 1 && MouseInRect(itemRect))
        {
            GenericMenu menu = new GenericMenu();
            menu.AddItem(new GUIContent("Build"), false, MenuBuild);

            Vector2 mousePos = Event.current.mousePosition;
            menu.DropDown(new Rect(mousePos.x, mousePos.y, 0, 0));
        }
    }

    void MenuBuild()
    {
        setting.Build(m_SelectedItems.ToArray(), encryptLua);
    }
}
